#include "sdk.h"
#include <wx/filedlg.h>
#include <wx/textdlg.h>
#include "filefilters.h"
#include "newfromtemplatedlg.h"

template<> TemplateManager* Mgr<TemplateManager>::instance = nullptr;
template<> bool  Mgr<TemplateManager>::isShutdown = false;

TemplateManager::TemplateManager() {
  Manager::Get()->GetAppWindow()->PushEventHandler( this );
}

TemplateManager::~TemplateManager() {
}

void TemplateManager::CreateMenu( M_Code_unused wxMenuBar* menuBar ) {
}

void TemplateManager::ReleaseMenu( M_Code_unused wxMenuBar* menuBar ) {
}

void TemplateManager::BuildToolsMenu( M_Code_unused wxMenu* menu ) {
}

void TemplateManager::LoadUserTemplates() {
  m_UserTemplates.Clear();
  wxString baseDir = ConfigManager::GetConfigFolder() + wxFILE_SEP_PATH + _T( "UserTemplates" );
  if( !wxDirExists( baseDir ) ) {
    return;
  }
  wxDir dir( baseDir );
  if( !dir.IsOpened() ) {
    return;
  }
  wxString filename;
  bool ok = dir.GetFirst( &filename, _T( "*" ), wxDIR_DIRS );
  while( ok ) {
    m_UserTemplates.Add( filename );
    ok = dir.GetNext( &filename );
  }
  Manager::Get()->GetLogManager()->DebugLog( F( _T( "%d user templates loaded" ), m_UserTemplates.GetCount() ) );
}

M_Code_Project* TemplateManager::New( TemplateOutputType initial, wxString* pFilename ) {
  M_Code_Project* prj = NULL;
  LoadUserTemplates();
  NewFromTemplateDlg dlg( initial, m_UserTemplates );
  PlaceWindow( &dlg );
  if( dlg.ShowModal() == wxID_OK ) {
    if( dlg.SelectedUserTemplate() ) {
      prj = NewProjectFromUserTemplate( dlg, pFilename );
    } else
    { prj = NewFromTemplate( dlg, pFilename ); }
  }
  return prj;
}

M_Code_Project* TemplateManager::NewFromTemplate( NewFromTemplateDlg& dlg, wxString* pFilename ) {
  M_Code_Project* prj = NULL;
  cbWizardPlugin* wiz = dlg.GetWizard();
  if( wiz ) {
    CompileTargetBase* ret = wiz->Launch( dlg.GetWizardIndex(), pFilename );
    switch( wiz->GetOutputType( dlg.GetWizardIndex() ) ) {
      case totProject:
        prj = dynamic_cast<M_Code_Project*>( ret );
        break;
      case totTarget:
      case totFiles:
      case totCustom:
      case totUser:
      default:
        break;
    }
  }
  return prj;
}

M_Code_Project* TemplateManager::NewProjectFromUserTemplate( NewFromTemplateDlg& dlg, wxString* pFilename ) {
  M_Code_Project* prj = NULL;
  if( !dlg.SelectedUserTemplate() ) {
    Manager::Get()->GetLogManager()->DebugLog( _T( "TemplateManager::NewProjectFromUserTemplate() called when no user template was selected ?!?" ) );
    return NULL;
  }
  wxString path = Manager::Get()->GetConfigManager( _T( "template_manager" ) )->Read( _T( "/projects_path" ) );
  wxString sep = wxFileName::GetPathSeparator();
  path = ChooseDirectory( nullptr, _T( "Choose a directory to create the new project" ),
                          path, _T( "" ), false, true );
  if( path.IsEmpty() ) {
    return NULL;
  } else if( path.Mid( path.Length() - 1 ) == wxFILE_SEP_PATH ) {
    path.RemoveLast();
  }
  if( wxDirExists( path ) ) {
    wxDir dir( path );
    if( dir.HasFiles() || dir.HasSubDirs() ) {
      if( msging( path + _T( " already contains other files.\n"
                             "If you continue, files with the same names WILL BE OVERWRITTEN.\n"
                             "Are you sure you want to continue?" ),
                  _T( "Files exist in directory" ), wxICON_EXCLAMATION | wxYES_NO | wxNO_DEFAULT ) != wxID_YES ) {
        return nullptr;
      }
    }
  }
  wxBusyCursor busy;
  wxString templ = ConfigManager::GetConfigFolder() + wxFILE_SEP_PATH + _T( "UserTemplates" );
  templ << sep << dlg.GetSelectedUserTemplate();
  if( !wxDirExists( templ ) ) {
    Manager::Get()->GetLogManager()->DebugLog( F( _T( "Cannot open user-template source path '%s'!" ), templ.wx_str() ) );
    return NULL;
  }
  wxString project_filename;
  wxArrayString files;
  wxDir::GetAllFiles( templ, &files );
  int count = 0;
  int total_count = files.GetCount();
  for( size_t i = 0; i < files.GetCount(); ++i ) {
    wxFileName dstname( files[i] );
    dstname.MakeRelativeTo( templ + sep );
    wxString src = files[i];
    wxString dst = path + sep + dstname.GetFullPath();
    if( !CreateDirRecursively( dst ) ) {
      Manager::Get()->GetLogManager()->DebugLog( _T( "Failed creating directory for " ) + dst );
    }
    if( wxCopyFile( src, dst, true ) ) {
      if( FileTypeOf( dst ) == ftm_Code_Project ) {
        project_filename = dst;
      }
      ++count;
    } else
    { Manager::Get()->GetLogManager()->DebugLog( F( _T( "Failed copying %s to %s" ), src.c_str(), dst.c_str() ) ); }
  }
  if( count != total_count ) {
    msging( _T( "Some files could not be loaded with the template..." ), _T( "错误" ), wxICON_ERROR );
  } else {
    if( project_filename.IsEmpty() ) {
      msging( _T( "User-template saved successfully but no project file exists in it!" ) );
    } else {
      wxFileName fname( project_filename );
      wxString newname = cbGetTextFromUser( _T( "If you want, you can change the project's filename here (without extension):" ), _T( "Change project's filename" ), fname.GetName() );
      if( !newname.IsEmpty() && newname != fname.GetName() ) {
        fname.SetName( newname );
        wxRenameFile( project_filename, fname.GetFullPath() );
        project_filename = fname.GetFullPath();
      }
      prj = Manager::Get()->GetProjectManager()->LoadProject( project_filename );
      if( prj && !newname.IsEmpty() ) {
        prj->SetTitle( newname );
        for( int i = 0; i < prj->GetBuildTargetsCount(); ++i ) {
          ProjectBuildTarget* bt = prj->GetBuildTarget( i );
          TargetFilenameGenerationPolicy tgfpPrefix, tgfpExtension;
          bt->GetTargetFilenameGenerationPolicy( tgfpPrefix, tgfpExtension );
          wxString outputFileName = bt->GetOutputFilename();
          wxFileName outFname( outputFileName );
          if( tgfpPrefix == tgfpPlatformDefault && bt->GetTargetType() == ttStaticLib ) {
            Compiler* projectCompiler = CompilerFactory::GetCompiler( bt->GetCompilerID() );
            if( projectCompiler )
            { newname.Prepend( projectCompiler->GetSwitches().libPrefix ); }
          }
          outFname.SetName( newname );
          bt->SetOutputFilename( outFname.GetFullPath() );
        }
        Manager::Get()->GetProjectManager()->GetUI().RebuildTree();
        CodeBlocksEvent evt( cbEVT_PROJECT_OPEN, 0, prj );
        Manager::Get()->ProcessEvent( evt );
      }
    }
  }
  if( prj && pFilename ) {
    *pFilename = prj->GetFilename();
  }
  return prj;
}

void TemplateManager::SaveUserTemplate( M_Code_Project* prj ) {
  if( !prj ) {
    return;
  }
  if( !prj->SaveAllFiles() ||
      !prj->Save() ) {
    msging( _T( "Could not save project and/or all its files. Aborting..." ), _T( "错误" ), wxICON_ERROR );
    return;
  }
  wxString templ = ConfigManager::GetConfigFolder() + wxFILE_SEP_PATH + _T( "UserTemplates" );
  if( !CreateDirRecursively( templ, 0755 ) ) {
    msging( _T( "Couldn't create directory for user templates:\n" ) + templ, _T( "错误" ), wxICON_ERROR );
    return;
  }
  wxString title = prj->GetTitle();
  wxFileName titleFileName( title ) ;
  wxString forbidden = titleFileName.GetForbiddenChars();
  for( size_t i = 0; i < forbidden.Length(); ++i ) {
    title.Replace( wxString( forbidden[i] ), _T( "" ), true );
  }
  while( true ) {
    wxTextEntryDialog dlg( nullptr, _T( "Enter a title for this template" ), _T( "Enter title" ), title );
    PlaceWindow( &dlg );
    if( dlg.ShowModal() != wxID_OK ) {
      return;
    }
    title = dlg.GetValue();
    if( !wxDirExists( templ + wxFILE_SEP_PATH + title ) ) {
      templ << wxFILE_SEP_PATH << title;
      wxMkdir( templ, 0755 );
      break;
    } else {
      msging( _T( "You have another template with the same title.\nPlease choose another title..." ) );
    }
  }
  wxBusyCursor busy;
  int count = 0;
  int total_count = prj->GetFilesCount();
  templ << wxFILE_SEP_PATH;
  wxFileName fname;
  for( FilesList::iterator it = prj->GetFilesList().begin(); it != prj->GetFilesList().end(); ++it ) {
    wxString src = ( *it )->file.GetFullPath();
    wxString dst = templ + ( *it )->relativeToCommonTopLevelPath;
    Manager::Get()->GetLogManager()->DebugLog( F( _T( "Copying %s to %s" ), src.c_str(), dst.c_str() ) );
    if( !CreateDirRecursively( dst ) ) {
      Manager::Get()->GetLogManager()->DebugLog( _T( "Failed creating directory for " ) + dst );
    }
    if( wxCopyFile( src, dst, true ) ) {
      ++count;
    } else
    { Manager::Get()->GetLogManager()->DebugLog( F( _T( "Failed copying %s to %s" ), src.c_str(), dst.c_str() ) ); }
  }
  wxString topLevelPath = prj->GetCommonTopLevelPath();
  fname.Assign( prj->GetFilename() );
  fname.MakeRelativeTo( topLevelPath );
  fname.Assign( templ + fname.GetFullPath() );
  if( !CreateDirRecursively( fname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ), 0755 ) ) {
    msging( _T( "Failed to create the directory for the project file!" ), _T( "错误" ), wxICON_ERROR );
    ++count;
  } else {
    if( !wxCopyFile( prj->GetFilename(), fname.GetFullPath() ) ) {
      Manager::Get()->GetLogManager()->DebugLog( _T( "Failed to copy the project file: " ) + fname.GetFullPath() );
      msging( _T( "Failed to copy the project file!" ), _T( "错误" ), wxICON_ERROR );
      ++count;
    }
  }
  if( count == total_count ) {
    msging( _T( "User-template saved successfully" ), _T( "Information" ), wxICON_INFORMATION | wxOK );
  } else {
    msging( _T( "Some files could not be saved with the template..." ), _T( "错误" ), wxICON_ERROR );
  }
}
